package main;

import java.awt.Button;
import java.awt.Choice;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import terrain.*;

public class BarrierBattle extends Battle {
	
	public LowWallRect barrier;
	
	public int defenderIndex;
	public ArrayList<Unit> perishedUnits = new ArrayList<Unit>();
	
	public boolean attackFromBothSides = false;
	
	public BarrierBattle(Game g, LowWallRect t){
		super(g);
		this.barrier = t;
	}
	
	public void setDefender(int index){
		this.defenderIndex = index;
		this.chargerIndex = (this.defenderIndex+1)%2;
	}
	
	public void setDefender(Unit u){
		this.defenderIndex = u.armyIndex;
		this.chargerIndex = (this.defenderIndex+1)%2;
	}
	
	public ArrayList<Unit> getDefenders(){
		if (this.defenderIndex == Game.GOODINDEX)
			return this.goodUnits;
		else if (this.defenderIndex == Game.BADINDEX)
			return this.badUnits;
		else
			return null;
	}
	
	public ArrayList<Unit> getAttackers(){
		if (this.defenderIndex == Game.GOODINDEX)
			return this.badUnits;
		else if (this.defenderIndex == Game.BADINDEX)
			return this.goodUnits;
		else
			return null;
	}
	
	public void importBattle(Battle b){
		this.badUnits = b.badUnits;
		this.goodUnits = b.goodUnits;
		this.losers = b.losers;
		this.winners = b.winners;
		this.myUI = b.myUI;
		this.victor = b.victor;
		for (Unit u : this.badUnits)
			u.battle = this;
		for (Unit u : this.goodUnits)
			u.battle = this;
		this.chargerIndex = b.chargerIndex;
	}
	
	public void rollBarrierFightDice(Button doneRetreating, Button barrierStrike, Choice attackerChoice, Choice targetChoice) {
		ArrayList<DieRoll> goodRolls = new ArrayList<DieRoll>();
		ArrayList<DieRoll> badRolls = new ArrayList<DieRoll>();
		int goodFV = 0;
		int badFV = 0;
		boolean mightPossible = false;
		// Roll the dice
		int dieCount = 1;
		for (Unit u : goodUnits) {
			u.hasFought = true;
			if (u.getFightValue() > goodFV)
				goodFV = u.getFightValue();
			for (int i = 0; i < u.getBattleDice(); i++) {
				DieRoll goodRoll = new DieRoll(u, myUI.dim.width-200, myUI.dim.height/2-90-30*(dieCount++), u.getBattleBonus(), u.toChoiceString(), myUI);
				goodRolls.add(goodRoll);
				if (goodRoll.useMight.isEnabled())
					mightPossible = true;
			}
		}
		dieCount = 1;
		for (Unit u : badUnits) {
			u.hasFought = true;
			if (u.getFightValue() > badFV)
				badFV = u.getFightValue();
			for (int i = 0; i < u.getBattleDice(); i++) {
				DieRoll badRoll = new DieRoll(u, myUI.dim.width-200, myUI.dim.height/2-90+30*(dieCount++), u.getBattleBonus(), u.toChoiceString(), myUI);
				badRolls.add(badRoll);
				if (badRoll.useMight.isEnabled())
					mightPossible = true;
			}
		}
		
		// None of our rollers can use might
		if (mightPossible == false){
			UI.messageLog.add("Good rolls, fightValue: " + goodRolls.toString() + ", " + goodFV);
			UI.messageLog.add("Bad rolls, fightValue: " + badRolls.toString() + ", " + badFV);
			
			int goodMax = 0;
			for (DieRoll dr : goodRolls) {
				if (goodMax < dr.getRoll())
					goodMax = dr.getRoll();
			}
			int badMax = 0;
			for (DieRoll dr : badRolls) {
				if (badMax < dr.getRoll())
					badMax = dr.getRoll();
			}
			
			if (goodMax > badMax || (goodMax == badMax && goodFV > badFV) ||
					(goodMax == badMax && goodFV == badFV && rng.nextInt(2) == 0)) {
				UI.messageLog.add("Good wins");
				this.victor = Game.GOODINDEX;
				this.winners = this.goodUnits;
				this.losers = this.badUnits;
			}
			else {
				UI.messageLog.add("Bad wins");
				this.victor = Game.BADINDEX;
				this.winners = this.badUnits;
				this.losers = this.goodUnits;
			}
			
			// If the defender won, the attackers need to back off
			if (this.victor == this.defenderIndex){
				for (Unit u : this.losers){
					u.uncontactTerrain();
					u.uncontactUnits();
					u.moveLeft = 1;
					if (u instanceof Hero && ((Hero)u).hasFury)
						((Hero)u).hasFury = false;
					for (Unit ally : game.armies[(this.victor+1)%2].units) {
						if (Utils.inchDist(u, ally) < 2 && ally.battle == null) {
							ally.moveLeft = 1;
						}
					}
				}
			}
			
			
			if (victor == defenderIndex)
				doneRetreating.setVisible(true);  // If the defenders won, treat the fight like a normal fight from here on out
			
			
			else {
				// Add strike paraphernalia
				for (Unit u : myUI.selectedBattle.winners) {
					for (int i = 0; i < u.getWoundDice(); i++) {
						attackerChoice.add(u.toChoiceString());
					}
				}
				for (Unit u : myUI.selectedBattle.losers) {
					if (u instanceof Hero && ((Hero)u).hasFury)
						((Hero)u).hasFury = false;
					targetChoice.add(u.toChoiceString());
				}
				myUI.add(attackerChoice);
				myUI.add(targetChoice);
				barrierStrike.setVisible(true); // Otherwise, attacker gets to strike
			}
			myUI.reenableComponents();
			myUI.repaint();
		}
		// Otherwise we can use might
		else {
			final int goodFVfinal = goodFV;
			final int badFVfinal = badFV;
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add("Good rolls, fightValue: " + goodRolls.toString() + ", " + goodFVfinal);
					UI.messageLog.add("Bad rolls, fightValue: " + badRolls.toString() + ", " + badFVfinal);
					
					int goodMax = 0;
					for (DieRoll dr : goodRolls) {
						if (goodMax < dr.getRoll())
							goodMax = dr.getRoll();
					}
					int badMax = 0;
					for (DieRoll dr : badRolls) {
						if (badMax < dr.getRoll())
							badMax = dr.getRoll();
					}
					
					if (goodMax > badMax || (goodMax == badMax && goodFVfinal > badFVfinal) ||
							(goodMax == badMax && goodFVfinal == badFVfinal && rng.nextInt(2) == 0)) {
						UI.messageLog.add("Good wins");
						victor = Game.GOODINDEX;
						winners = goodUnits;
						losers = badUnits;
					}
					else {
						UI.messageLog.add("Bad wins");
						victor = Game.BADINDEX;
						winners = badUnits;
						losers = goodUnits;
					}
					
					// If the defender won, the attackers need to back off
					if (victor == defenderIndex){
						for (Unit u : losers){
							u.uncontactTerrain();
							u.uncontactUnits();
							u.moveLeft = 1;
							if (u instanceof Hero && ((Hero)u).hasFury)
								((Hero)u).hasFury = false;
							for (Unit ally : game.armies[(victor+1)%2].units) {
								if (Utils.inchDist(u, ally) < 2 && ally.battle == null) {
									ally.moveLeft = 1;
								}
							}
						}
					}
					
					if (victor == defenderIndex)
						doneRetreating.setVisible(true);  // If the defenders won, treat the fight like a normal fight from here on out
					else {
						// Add strike paraphernalia
						for (Unit u : myUI.selectedBattle.winners)	{
							for (int i = 0; i < u.getWoundDice(); i++) {
								attackerChoice.add(u.toChoiceString());
							}
						}
						for (Unit u : myUI.selectedBattle.losers) {
							targetChoice.add(u.toChoiceString());
							if (u instanceof Hero && ((Hero)u).hasFury)
								((Hero)u).hasFury = false;
						}
						myUI.add(attackerChoice);
						myUI.add(targetChoice);
						barrierStrike.setVisible(true); // Otherwise, attacker gets to strike
					}
					
					for (DieRoll dr : goodRolls)
						dr.cleanup();
					for (DieRoll dr : badRolls)
						dr.cleanup();
					myUI.disableMight();
					myUI.reenableComponents();
					myUI.repaint();
				}
			};
			myUI.enableMight(mightDone);
		}
	}
	
	// For use in multiple attackers vs. one target situations, where attacks come in individually
	public void rollDiceOneAttacker(Unit attacker, Button doneRetreating, Button barrierStrike, Choice attackerChoice, Choice targetChoice) {
		Unit defender = this.getDefenders().get(0);
		ArrayList<DieRoll> attackRolls = new ArrayList<DieRoll>();
		ArrayList<DieRoll> defendRolls = new ArrayList<DieRoll>();
		int attackFV = attacker.getFightValue();
		int defendFV = defender.getFightValue();
		
		defender.hasFought = true;
		attacker.hasFought = true;
		boolean mightPossible = false;
		
		// Roll dice - defender
		for (int i = 0; i < defender.battleDice+Math.min(1, defender.supporters.size()); i++) {
			DieRoll defRoll = new DieRoll(defender, myUI.dim.width-200, myUI.dim.height/2-90-30*(i+1), defender.getBattleBonus(), defender.toChoiceString(), myUI);
			defendRolls.add(defRoll);
			if (defRoll.useMight.isEnabled())
				mightPossible = true;
		}
		// Roll dice - attacker
		for (int i = 0; i < attacker.battleDice+Math.min(1, attacker.supporters.size()); i++) {
			DieRoll attackRoll = new DieRoll(attacker, myUI.dim.width-200, myUI.dim.height/2-90+30*(i+1), attacker.getBattleBonus(), attacker.toChoiceString(), myUI);
			attackRolls.add(attackRoll);
			if (attackRoll.useMight.isEnabled())
				mightPossible = true;
		}
		
		
		// Can't use might
		if (mightPossible == false) {
			UI.messageLog.add("Attacker rolls, fightValue: " + attackRolls.toString() + ", " + attackFV);
			UI.messageLog.add("Defender rolls, fightValue: " + defendRolls.toString() + ", " + defendFV);
			int defendMax = 0;
			for (DieRoll dr : defendRolls){
				if (dr.getRoll() < defendMax)
					defendMax = dr.getRoll();
			}
			int attackMax = 0;
			for (DieRoll dr : attackRolls){
				if (dr.getRoll() < attackMax)
					attackMax = dr.getRoll();
			}
			
			// Check who wins
			if (defendMax > attackMax || (defendMax == attackMax && defendFV > attackFV) ||
					(defendMax == attackMax && defendFV == attackFV && rng.nextInt(2) == 0)) {
				// Defender wins
				UI.messageLog.add("Defender wins");
				this.victor = this.defenderIndex;
				this.winners = this.getDefenders();
				this.losers = new ArrayList<Unit>();
				this.losers.add(attacker);
			}
			else {
				// Attacker wins
				UI.messageLog.add("Attacker wins");
				this.victor = attacker.armyIndex;
				this.losers = this.getDefenders();
				this.winners = new ArrayList<Unit>();
				this.winners.add(attacker);
			}
			// If the defender won, the attackers need to back off
			if (this.victor == this.defenderIndex){
				for (Unit u : this.losers){
					u.uncontactTerrain();
					u.uncontactUnits();
					u.moveLeft = 1;
					if (u instanceof Hero && ((Hero)u).hasFury)
						((Hero)u).hasFury = false;
					for (Unit ally : game.armies[(this.victor+1)%2].units) {
						if (Utils.inchDist(u, ally) < 2 && ally.battle == null) {
							ally.moveLeft = 1;
						}
					}
				}
			}
			// If attacker won...
			if (myUI.selectedBattle.victor == attacker.armyIndex) {
				// Set up barrier strike options and enable them
				for (Unit u : myUI.selectedBattle.winners) {
					for (int i = 0; i < u.getWoundDice(); i++) {
						attackerChoice.add(u.toChoiceString());
					}
				}
				for (Unit u : myUI.selectedBattle.losers) {
					targetChoice.add(u.toChoiceString());
					if (u instanceof Hero && ((Hero)u).hasFury)
						((Hero)u).hasFury = false;
				}
				myUI.add(attackerChoice);
				myUI.add(targetChoice);
				
				barrierStrike.setVisible(true);
			}
			// Otherwise defender won
			else {
				doneRetreating.setVisible(true);
			}
			for (DieRoll dr : attackRolls)
				dr.cleanup();
			for (DieRoll dr : defendRolls)
				dr.cleanup();
			myUI.reenableComponents();
			myUI.repaint();
		}
		// Otherwise, we have might
		else {
			ActionListener mightDone = new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					UI.messageLog.add("Attacker rolls, fightValue: " + attackRolls.toString() + ", " + attackFV);
					UI.messageLog.add("Defender rolls, fightValue: " + defendRolls.toString() + ", " + defendFV);
					int defendMax = 0;
					for (DieRoll dr : defendRolls){
						if (dr.getRoll() < defendMax)
							defendMax = dr.getRoll();
					}
					int attackMax = 0;
					for (DieRoll dr : attackRolls){
						if (dr.getRoll() < attackMax)
							attackMax = dr.getRoll();
					}
					
					// Check who wins
					if (defendMax > attackMax || (defendMax == attackMax && defendFV > attackFV) ||
							(defendMax == attackMax && defendFV == attackFV && rng.nextInt(2) == 0)) {
						// Defender wins
						UI.messageLog.add("Defender wins");
						victor = defenderIndex;
						winners = getDefenders();
						losers = new ArrayList<Unit>();
						losers.add(attacker);
					}
					else {
						// Attacker wins
						UI.messageLog.add("Attacker wins");
						victor = attacker.armyIndex;
						losers = getDefenders();
						winners = new ArrayList<Unit>();
						winners.add(attacker);
					}
					// If the defender won, the attackers need to back off
					if (victor == defenderIndex){
						for (Unit u : losers){
							u.uncontactTerrain();
							u.uncontactUnits();
							u.moveLeft = 1;
							if (u instanceof Hero && ((Hero)u).hasFury)
								((Hero)u).hasFury = false;
							for (Unit ally : game.armies[(victor+1)%2].units) {
								if (Utils.inchDist(u, ally) < 2 && ally.battle == null) {
									ally.moveLeft = 1;
								}
							}
						}
					}
					// If attacker won...
					if (myUI.selectedBattle.victor == attacker.armyIndex) {
						// Set up barrier strike options and enable them
						for (Unit u : myUI.selectedBattle.winners) {
							if (u instanceof Hero && ((Hero)u).hasFury)
								((Hero)u).hasFury = false;
							if (u.layingDown) {
								// Stand up
								System.out.println("SHOULD NEVER HAPPEN, CHARGED A BARRIER WHILE LAYING DOWN");
							}
							else {
								for (int i = 0; i < u.getWoundDice(); i++) {
									attackerChoice.add(u.toChoiceString());
								}
							}
						}
						for (Unit u : myUI.selectedBattle.losers) {
							targetChoice.add(u.toChoiceString());
						}
						myUI.add(attackerChoice);
						myUI.add(targetChoice);
						
						barrierStrike.setVisible(true);
					}
					// Otherwise defender won
					else {
						doneRetreating.setVisible(true);
					}
					for (DieRoll dr : attackRolls)
						dr.cleanup();
					for (DieRoll dr : defendRolls)
						dr.cleanup();
					myUI.disableMight();
					myUI.reenableComponents();
					myUI.repaint();
				}
			};
			myUI.enableMight(mightDone);
		}
	}
}
